package com.lemon.utils;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.google.api.services.youtube.model.VideoSnippet;
import com.google.api.services.youtube.model.VideoStatus;
import com.lemon.dto.MyVideo;
import com.lemon.feign.BilibiliFeign;
import feign.FeignException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.*;

@Component
@Slf4j
public class BilibiliUtil {
    static public final String AGENT = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36";
    static public final String COOKIE = "i-wanna-go-back=-1; buvid_fp_plain=undefined; blackside_state=0; CURRENT_BLACKGAP=0; rpdid=|(RlRkl|uJ~0J'uYY)~J~YRR; buvid4=4064EEC4-C080-27D2-CC5B-C7A9C0926EB667626-022021411-%2BZCMR%2B2k%2F7A1yLPRmWQHlw%3D%3D; LIVE_BUVID=AUTO8816762793753374; buvid3=17C4FCD2-EA50-BDCC-766A-E90232F27A3820097infoc; b_nut=1676518420; _uuid=AA1710AB9-F1010D-DE5C-C9E4-DBAF8E126D1B20144infoc; nostalgia_conf=-1; CURRENT_PID=7f96a1f0-ceee-11ed-99aa-d1e74d5467ad; hit-new-style-dyn=1; hit-dyn-v2=1; CURRENT_FNVAL=4048; is-2022-channel=1; bp_t_offset_162981410=798483778356903991; fingerprint=84b35a303be3a66d1cd8b681bd7aa580; PVID=3; bsource=search_baidu; b_lsid=C1BA910D3_1888ACDD1B6; buvid_fp=8b4edabe0cf33a10852bd9ece3b1ff07; b_ut=7; FEED_LIVE_VERSION=V8; header_theme_version=CLOSE; home_feed_column=4; SESSDATA=c4af47b0%2C1701509286%2Ceb60a%2A62; bili_jct=c8938e81809d83b18966e30c2b02d85c; DedeUserID=162981410; DedeUserID__ckMd5=72575eb890793f39; browser_resolution=307-969; sid=gi8lzmcy; CURRENT_QUALITY=64";

    @Autowired
    BilibiliFeign bilibiliFeign;

    @Value("${bvid-path}")
    String bvidPath;

    @Value("${video-path}")
    String videoPath;

    @Value("${pic-path}")
    String picPath;

    @Value("${batch-video-count}")
    Integer batchVideoCount;

    @Value("${bilibili.order}")
    String order;

    @Autowired
    BiliBiliHttpInterface biliBiliHttpInterface;

    public List<MyVideo> getMyVideosByUid(String uid, String upName, String tagDef, Set<String> bvidSet) {
        List<MyVideo> myVideoList = new ArrayList<>();
        Integer j = 0;
        while (myVideoList.size() < batchVideoCount) {
            String search =null;
            try {
                try {
                    search = biliBiliHttpInterface.search(uid, ++j);
                } catch (FeignException e) {
                    Thread.sleep(3000);
                    if (e.status() == 421) {
                        log.error("接口421错误");
                    }
                    throw e;
                }
                if (search.startsWith("{\"code\":-509,\"message\":\"请求过于频繁，请稍后再试\",\"ttl\":1}")) {
                    search = search.substring("{\"code\":-509,\"message\":\"请求过于频繁，请稍后再试\",\"ttl\":1}".length());
                }
                JSONObject searchJsonObject = JSONObject.parseObject(search);
                if (!searchJsonObject.getString("code").equals("0")) {
                    log.error("关键字搜索错误,{}", search);
                    return myVideoList;
                }
                JSONArray jsonArray = searchJsonObject.getJSONObject("data").getJSONObject("list").getJSONArray("vlist");
                for (int i = 0; i < jsonArray.size(); i++) {
                    if (myVideoList.size() >= batchVideoCount) {
                        // 每次最多获取视频个数
                        break;
                    }
                    try {
                        JSONObject obj = jsonArray.getJSONObject(i);
                        String tag = obj.getString("tag");
                        String bvid = obj.getString("bvid");
                        if (StringUtils.isEmpty(bvid)) {
                            continue;
                        }
                        // 对比是否上传过 若上传过 则跳过这个视频
                        if (bvidSet.contains(bvid)) {
                            log.warn("该视频已上传过 bvid:{}", bvid);
                            continue;
                        }

                        String view = bilibiliFeign.view(AGENT, COOKIE, bvid);
                        JSONObject viewObject = JSONObject.parseObject(view);
                        JSONObject viewData = viewObject.getJSONObject("data");
                        String picUrl = viewData.getString("pic");
                        String title = "【" + upName + "】" + viewData.getString("title");
                        String desc = viewData.getString("desc");
                        String cid = viewData.getJSONArray("pages").getJSONObject(0).getString("cid");
                        String urlJson = bilibiliFeign.videoUrl(AGENT, COOKIE, "1", "80", bvid, cid);
                        String urlStr = JSONObject.parseObject(urlJson).getJSONObject("data").getJSONArray("durl").getJSONObject(0).getString("url");
                        MyVideo myVideo = new MyVideo();
                        downLoaderPic(picUrl, bvid, myVideo);
                        downLoader(urlStr, bvid, myVideo);
                        if (StringUtils.isNotEmpty(myVideo.getUrlPath())) {
                            //构造 MyVideo
                            myVideoList.add(myVideo);
                            myVideo.setCid(cid);
                            myVideo.setBvid(bvid);
                            // 构造一个 youtube video
                            VideoStatus status = new VideoStatus();
                            status.setPrivacyStatus("public");
                            VideoSnippet snippet = new VideoSnippet();
                            snippet.setTitle(title);
                            if (StringUtils.isNotEmpty(desc) && !desc.equals("-")) {
                                snippet.setDescription(desc);
                            } else {
                                snippet.setDescription("想要一个赞赞.呜呜");
                            }
                            if (StringUtils.isNotEmpty(tag)) {
                                snippet.setTags(Arrays.asList(tag.split(",")));
                            } else {
                                snippet.setTags(Arrays.asList(tagDef.split(",")));
                            }
                            myVideo.getYoutubeVideo().setStatus(status).setSnippet(snippet);
                        }
                    } catch (Exception e) {
                        log.error("解析失败obj:{}", jsonArray.getJSONObject(i));
                    }
                }
            } catch (JSONException e) {
                log.error("json解析失败json:{}", search);
            }
            catch (Exception e) {
                log.error("接口调用异常。msg:{}", e.getMessage());
                break;
            }
        }
        return myVideoList;
    }


    public List<MyVideo> getMyVideos(String keyWord, Set<String> bvidSet) {
        List<MyVideo> myVideoList = new ArrayList<>();

        Integer j = 0;
        while (myVideoList.size() < batchVideoCount) {
            String search = bilibiliFeign.search(AGENT, COOKIE, "video", keyWord, order, (++j).toString());
            JSONObject searchJsonObject = JSONObject.parseObject(search);
            if (!searchJsonObject.getString("code").equals("0")) {
                log.error("关键字搜索错误,{}", search);
                return myVideoList;
            }
            JSONArray jsonArray = searchJsonObject.getJSONObject("data").getJSONArray("result");
            for (int i = 0; i < jsonArray.size(); i++) {
                if (myVideoList.size() >= batchVideoCount) {
                    // 每次最多获取视频个数
                    break;
                }
                try {
                    JSONObject obj = jsonArray.getJSONObject(i);
                    String tag = obj.getString("tag");
                    String bvid = obj.getString("bvid");
                    if (StringUtils.isEmpty(bvid)) {
                        continue;
                    }
                    // 对比是否上传过 若上传过 则跳过这个视频
                    if (bvidSet.contains(bvid)) {
                        log.warn("该视频已上传过 bvid:{}", bvid);
                        continue;
                    }

                    String view = bilibiliFeign.view(AGENT, COOKIE, bvid);
                    JSONObject viewObject = JSONObject.parseObject(view);
                    JSONObject viewData = viewObject.getJSONObject("data");
                    String title = viewData.getString("title");
                    String desc = viewData.getString("desc");
                    String cid = viewData.getJSONArray("pages").getJSONObject(0).getString("cid");
                    String urlJson = bilibiliFeign.videoUrl(AGENT, COOKIE, "1", "80", bvid, cid);
                    String urlStr = JSONObject.parseObject(urlJson).getJSONObject("data").getJSONArray("durl").getJSONObject(0).getString("url");

                    MyVideo myVideo = new MyVideo();
                    downLoader(urlStr, bvid, myVideo);
                    if (StringUtils.isNotEmpty(myVideo.getUrlPath())) {
                        //构造 MyVideo
                        myVideoList.add(myVideo);
                        myVideo.setCid(cid);
                        myVideo.setBvid(bvid);
                        // 构造一个 youtube video
                        VideoStatus status = new VideoStatus();
                        status.setPrivacyStatus("public");
                        VideoSnippet snippet = new VideoSnippet();
                        snippet.setTitle(title);
                        if (StringUtils.isNotEmpty(desc)) {
                            snippet.setDescription(desc);
                        }
                        if (StringUtils.isNotEmpty(tag)) {
                            snippet.setTags(Arrays.asList(tag.split(",")));
                        }
                        myVideo.getYoutubeVideo().setStatus(status).setSnippet(snippet);
                    }
                } catch (Exception e) {
                    log.error("解析失败obj:{}", jsonArray.getJSONObject(i));
                }
            }
        }
        return myVideoList;
    }

    private void downLoaderPic(String picUrl, String bvid, MyVideo myVideo) {
        InputStream input = null;
        FileOutputStream fos = null;
        String path = null;
        try {
            path = picPath + DateUtil.getyyyyMMddHHmmss() + "-" + bvid + ".jpg";
            long begin = System.currentTimeMillis();
            URL url = new URL(picUrl);
            URLConnection urlConnection = url.openConnection();
            urlConnection.setRequestProperty("Referer", "https://www.bilibili.com"); // 设置协议
            urlConnection.setRequestProperty("Sec-Fetch-Mode", "no-cors");
            urlConnection.setRequestProperty("User-Agent", AGENT);
            urlConnection.setConnectTimeout(10 * 1000);
            System.out.println("共:" + (urlConnection.getContentLength() / 1024) + "Kb");
            System.out.println("开始下载...");
            input = urlConnection.getInputStream();

            File file = new File(path);
            fos = new FileOutputStream(file);
            byte[] buffer = new byte[1024*1024];

            int count = 0;
            int num = 0;
            int i =0;
            while ((count = input.read(buffer, 0, buffer.length)) != -1) {
                fos.write(buffer, 0, count);
                num += count/1024;
                i++;
                if (i % 200 == 0) {
                    log.info("已下载:{}", num + "/" + (urlConnection.getContentLength() / 1024));
                }
            }
            long end = System.currentTimeMillis();
            log.info("耗时：" + (end - begin) / 1000 + "秒");
            log.info("图片下载完成！ bvid：{} 大小: {} kb", bvid, num + "/" + (urlConnection.getContentLength() / 1024));
            myVideo.setPicLen((long) urlConnection.getContentLength());
            myVideo.setPicPath(path);
        } catch (Exception e) {
            log.error("异常中止: " + e);
        } finally {
            try {
                if (input != null) {
                    input.close();
                }
                if (fos != null) {
                    fos.close();
                }
            } catch (Exception e) {
                log.error("download error",e);
            }
        }
    }

    void downLoader(String urlPath, String bvid, MyVideo myVideo) {
        String urlPath1 = urlPath;
        InputStream input = null;
        FileOutputStream fos = null;
        String path = null;
        try {
            path = videoPath + DateUtil.getyyyyMMddHHmmss() + "-" + bvid + ".mp4";
            long begin = System.currentTimeMillis();
            URL url = new URL(urlPath1);
            URLConnection urlConnection = url.openConnection();
            urlConnection.setRequestProperty("Referer", "https://www.bilibili.com"); // 设置协议
            urlConnection.setRequestProperty("Sec-Fetch-Mode", "no-cors");
            urlConnection.setRequestProperty("User-Agent", AGENT);
            urlConnection.setConnectTimeout(10 * 1000);
            System.out.println("共:" + (urlConnection.getContentLength() / 1024) + "Kb");
            System.out.println("开始下载...");
            input = urlConnection.getInputStream();

            File file = new File(path);
            fos = new FileOutputStream(file);
            byte[] buffer = new byte[1024*1024];

            int count = 0;
            int num = 0;
            int i =0;
            while ((count = input.read(buffer, 0, buffer.length)) != -1) {
                fos.write(buffer, 0, count);
                num += count/1024;
                i++;
                if (i % 200 == 0) {
                    log.info("已下载:{}", num + "/" + (urlConnection.getContentLength() / 1024));
                }
            }
            long end = System.currentTimeMillis();
            log.info("耗时：" + (end - begin) / 1000 + "秒");
            log.info("视频下载完成！ bvid：{} 大小: {} kb", bvid, num + "/" + (urlConnection.getContentLength() / 1024));
            myVideo.setVideoLen((long) urlConnection.getContentLength());
            myVideo.setUrlPath(path);
        } catch (Exception e) {
            log.error("异常中止: " + e);
        } finally {
            try {
                if (input != null) {
                    input.close();
                }
                if (fos != null) {
                    fos.close();
                }
            } catch (Exception e) {
                log.error("download error",e);
            }
        }
    }

    public static void main(String[] args) {
        InputStream input = null;
        FileOutputStream fos = null;
        String path = null;
        try {
            path = "D:\\code\\video\\" + DateUtil.getyyyyMMddHHmmss() + "-" + "BV1kF41177ab" + ".jpg";
            long begin = System.currentTimeMillis();
            URL url = new URL("http://i2.hdslb.com/bfs/archive/5c5b71d50af4a3e316ad94ab43456928ec983881.jpg");
            URLConnection urlConnection = url.openConnection();
            urlConnection.setRequestProperty("Referer", "https://www.bilibili.com"); // 设置协议
            urlConnection.setRequestProperty("Sec-Fetch-Mode", "no-cors");
            urlConnection.setRequestProperty("User-Agent", AGENT);
            urlConnection.setConnectTimeout(10 * 1000);
            System.out.println("共:" + (urlConnection.getContentLength() / 1024) + "Kb");
            System.out.println("开始下载...");
            input = urlConnection.getInputStream();

            File file = new File(path);
            fos = new FileOutputStream(file);
            byte[] buffer = new byte[1024*1024];

            int count = 0;
            int num = 0;
            int i =0;
            while ((count = input.read(buffer, 0, buffer.length)) != -1) {
                fos.write(buffer, 0, count);
                num += count/1024;
                i++;
                if (i % 200 == 0) {
                    log.info("已下载:{}", num + "/" + (urlConnection.getContentLength() / 1024));
                }
            }
            long end = System.currentTimeMillis();
            log.info("耗时：" + (end - begin) / 1000 + "秒");
            log.info("图片下载完成！ bvid：{} 大小: {} kb", "BV1kF41177ab", num + "/" + (urlConnection.getContentLength() / 1024));
            System.out.println((long) urlConnection.getContentLength());
            System.out.println(path);
        } catch (Exception e) {
            log.error("异常中止: " + e);
        } finally {
            try {
                if (input != null) {
                    input.close();
                }
                if (fos != null) {
                    fos.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }



}
